/**
 *
 * @author ihabali
 * @version 1.1
 * @className ExamModel
 * @date 1st April 2014
 * @Assignment 3 ETP
 * @see ExamController
 * 
 * This class will will communicate with the database through an EntityManager instance 
 * the class holds all the information fetched from the database . 
 * 
 * This a stateless EJB class , this means the properties of this class will not be removed by invalidating the http
 * session even when  the user logs out successfully. For this reason, it's necessary to call the method cleanUp()
 * between sessions to clean the run time stored values before logging out of the session .
 * 
 * An inner class StopWatchModel will be used in the view as a timer , only one instance will be created 
 * of this class and it will be held in the examModel. The controller only receive  an instance through a getter
 * to use it with view  .
 * 
 * 
 *
 * 
 */


package model;

import Entities.Exam;
import Entities.Questions;
import controller.LoginController;
import java.io.Serializable;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

/**
 *
 * @author ihabali
 */

@Stateless
public class ExamModel implements Serializable {
    private static final long serialVersionUID = 1L;
    private List<Exam> examsList ;
    private Map<String,String> examStringList;
    private String selectedExam ;
    private Exam selectedEx;
    private String description;
    private String duration;
    private String date;
    private StopwatchModel swm;
    private List<Questions> questionsList;
    private String savedAnswer;
    private  transient Logger logger = Logger.getLogger(ExamModel.class.getName());
    @PersistenceContext(name="Exam_PlayerPU")
    transient EntityManager em;
    
    
    
    public ExamModel() {
       examsList =  new ArrayList<>();
       questionsList = new ArrayList<>();
       
    }
    @PostConstruct
     private void populateList(){
        
        System.out.println("Populating exams list");
         TypedQuery<Exam> examsQuery = em.createNamedQuery("Exam.findAll", Exam.class);
         logger.info("query created");
         try {
           examsList =   examsQuery.getResultList();
           
         } catch (Exception e) {
            logger.log(Level.SEVERE , e.toString());
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("Couldn't load the exams "));
        }
        logger.info("examList populated");
        examStringList =  new LinkedHashMap<>();
        for(Exam ex : examsList){
             logger.info("examList has more than one entry");
            examStringList.put(ex.getTitle(),ex.getTitle());
        }
    }

    public Exam getSelectedEx() {
        return selectedEx;
    }

    public void setSelectedEx(Exam selectedEx) {
        this.selectedEx = selectedEx;
    }
     
     
     public String getSelectedExam() {
        return selectedExam;
    }

    public void setSelectedExam(String selectedExam) {
        System.out.println(selectedExam+"  Set");
        this.selectedExam = selectedExam;
        for(Exam ex : examsList){
            if(selectedExam.equalsIgnoreCase(ex.getTitle())){
                this.selectedEx = ex ; 
                break;
            }
        }
    }

    
    public Map<String,String> getExamStringList() {
        return examStringList;
    }

    public void setExamStringList(Map<String,String> examStringList) {
        this.examStringList = examStringList;
    }

    public String getDescription() {
       if(this.selectedEx != null){
           this.description = this.selectedEx.getExamdiscription();
           return this.description ;
       }
       return null;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDuration() {
        if(this.selectedEx != null){
           this.duration =selectedEx.getExamduration();
           return this.duration ;
       }
       return null;
    
    }

    public void setDuration(String duration) {
        this.duration = duration;
    }

    public String getDate() {
       if(this.selectedEx != null){
           this.date =SimpleDateFormat.getDateInstance().format(selectedEx.getExamdate());
            SimpleDateFormat sdf =  new SimpleDateFormat();     
            this.date = sdf.format(selectedEx.getExamdate());
           return this.date ;
       }
       return null;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public StopwatchModel getSwm() {
        return swm;
    }

    
    public void setTheQuestions(){
        
        if(this.selectedEx.getExamid() == 1){
            questionsList =  getRandomQuestion(3);
           this.selectedEx.setQuestionsList(questionsList); 
           
        }else  if(this.selectedEx.getExamid() == 2){
             questionsList =  getRandomQuestion(10);
             this.selectedEx.setQuestionsList(questionsList); 
             
        }else  if(this.selectedEx.getExamid() == 3){
            questionsList =  getRandomQuestion(15);
            this.selectedEx.setQuestionsList(questionsList);   
            
        }else{
           this.questionsList =  this.selectedEx.getQuestionsList();
        }
    }
   
    
    
    public void createSwm(){
        String hours ;
        String  minutes ;
        hours=  duration.substring(0, 2);
        minutes =duration.substring(3, 5);
       System.out.println(hours +"  hours  "+ minutes+"  minutes" );
        int hoursInt = Integer.parseInt(hours);
        int minutesInt = Integer.parseInt(minutes);
        swm = new StopwatchModel(hoursInt, minutesInt-1, 59);
        
    }  

   
    public void cleanUp(){
        for(Questions q :this.selectedEx.getQuestionsList()){
            q.setSavedanswer(null);
        }
       selectedExam = null;
       selectedEx = null;
       swm = null;
       
    }
    
    public List<Questions> getRandomQuestion(int number) {
         logger.info("generating random question");
        TypedQuery selectQuery = em.createNamedQuery("Questions.findAll", Questions.class);
        logger.info("query created to get the list of all questions");
        List<Questions> list = selectQuery.getResultList();
        logger.info("query excuted");
        ArrayList<Questions> temp = new ArrayList<>();
        Random random = new Random();
        while (temp.size() < number) {
            Questions q = list.get(random.nextInt(list.size()));
            if (!temp.contains(q)) {
                logger.info("picked up one random question");
                temp.add(q);
            }
        }
        return temp;
    }
    
  
    public class StopwatchModel implements Serializable {
   
    private  NumberFormat NF;
    private int hours;
    private boolean isRunning = true ;
    private int minutes ;
    private int seconds ;
    private boolean willExpireInTenSecs;
            
            
    public StopwatchModel(){
        this( 0, 0, 0 );
    }
    public StopwatchModel(int hours,int minutes ,int seconds){
        super();
       NF = NumberFormat.getInstance();
       NF.setMaximumIntegerDigits( 2 );
       NF.setMinimumIntegerDigits( 2 );
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
        
        if( minutes<0){
            this.minutes = 59;
            --this.hours;
        }
    }
    
    
   public boolean isIsRunning() {
        return isRunning;
    }
    
    public boolean handleTimer(){
        if(seconds<= 0 && minutes <= 0 && hours <= 0){
            isRunning = false;
            return true;
        }
        isRunning = true;
        --seconds;
        if(seconds < 0 && minutes > 0){
            seconds = 59;
            --minutes ;
            if (minutes <= 0 && hours>0){
                --hours;
                minutes = 59;
            }
        }
        return hours == 0 && minutes == 0 && seconds < 11;
    }
    public int getSeconds(){
        return seconds;
    }
    @Override
    public String toString(){
        return( NF.format(hours) + ":" + NF.format(minutes) + ":" + NF.format(seconds) );
    }
}
}
